using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Xml;
using CosyTrade.Core;
using CosyTrade.Network;
using CosyTrade.Security;
using Module=CosyTrade.Security.Module;

namespace CosyTrade.UI
{
    [Addin("AddinFormManager")]
    public class AddinFormManager : AddinBase, IAddinFormManager
    {
        private MainFormBase mainForm;
        private IList<IMenuItem> rootMenus;
        private readonly Dictionary<string, string> functionTypeMapping = new Dictionary<string, string>();
        private readonly Dictionary<string, AddinFormBase> runningAddinForm = new Dictionary<string, AddinFormBase>();

        protected override void OnInitialize()
        {
            XmlNodeList loaderNode = ConfigNode.SelectNodes("Modules/ModuleLoader");
            foreach (XmlNode node in loaderNode)
            {
                string loaderAddinKey = node.Attributes["key"].InnerText;
                XmlNodeList functionsNode = node.SelectNodes("Function");
                foreach (XmlNode xmlNode in functionsNode)
                    functionTypeMapping.Add(xmlNode.Attributes["key"].InnerText, loaderAddinKey);
            }
        }

        public MainFormBase MainForm
        {
            get
            {
                if (mainForm == null) LoadMainForm();
                return mainForm;
            }
        }

        public IList<IMenuItem> RootMenus
        {
            get
            {
                if (rootMenus == null) LoadRootMenus();
                return rootMenus;
            }
        }

        public AddinFormBase GetAddinForm(string functionKey)
        {
            if (runningAddinForm.ContainsKey(functionKey)) return runningAddinForm[functionKey];

            if (!functionTypeMapping.ContainsKey(functionKey)) throw new Exception("Not Found FunctionKey");

            IUILoader uiLoader = (IUILoader) CurrentAddinManager.GetAddin(functionTypeMapping[functionKey]);
            Type loadType = uiLoader.GetFunctionUIType(functionKey);
            AddinFormBase addinForm = (AddinFormBase) Activator.CreateInstance(loadType);
            if (addinForm == null)
                throw new Exception(string.Format("Can't create AddinFormInstance FunctionKey:{0}", functionKey));

            SystemStat systemStat =
                ((ISystemStatCenter) CurrentAddinManager.GetAddin("SystemStatCenter")).GetSystemStat();
            IRemotingPortalFactory proxyMgr = (IRemotingPortalFactory)CurrentAddinManager.GetAddin(ConfigNode["PortalFactory"].InnerText);
            AddinFormSetValue(addinForm, "functionKey", functionKey);
            AddinFormSetValue(addinForm, "currentSystemStat", systemStat);
            AddinFormSetValue(addinForm, "currentAddinManager", CurrentAddinManager);
            AddinFormSetValue(addinForm, "currentPortalFactory", proxyMgr);
            AddinFormSetValue(addinForm, "currentFunctionPowerSet", proxyMgr.GetProxy<ISecuritySystem>().GetRolePowerSet(functionKey, systemStat.UserRole.PrimaryKey));
            AddinFormSetValue(addinForm, "mainForm", mainForm);
            AddinFormSetValue(addinForm, "currentStatbarController", mainForm.GetStatbarController());
            addinForm.FormClosed += new System.Windows.Forms.FormClosedEventHandler(addinForm_FormClosed);
            runningAddinForm.Add(functionKey, addinForm);
            return addinForm;
        }

        private void addinForm_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
        {
            runningAddinForm.Remove(((AddinFormBase) sender).FunctionKey);
        }

        private static void AddinFormSetValue(AddinFormBase addinForm, string fieldName, object value)
        {
            FieldInfo fieldInfo =
                addinForm.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
            fieldInfo.SetValue(addinForm, value);
        }

        private void LoadMainForm()
        {
            mainForm = new MainForm();

            Type mainFormType = mainForm.GetType();

            FieldInfo systemStatField = mainFormType.GetField("currentSystemStat", BindingFlags.Instance | BindingFlags.NonPublic);
            ISystemStatCenter systemStatCenter = (ISystemStatCenter) CurrentAddinManager.GetAddin("SystemStatCenter");
            systemStatField.SetValue(mainForm, systemStatCenter.GetSystemStat());

            FieldInfo addinMgrField = mainFormType.GetField("currentAddinManager", BindingFlags.Instance | BindingFlags.NonPublic);
            addinMgrField.SetValue(mainForm, CurrentAddinManager);

            FieldInfo proxyMgrField = mainFormType.GetField("currentPortalFactory", BindingFlags.Instance | BindingFlags.NonPublic);
            proxyMgrField.SetValue(mainForm, CurrentAddinManager.GetAddin(ConfigNode["PortalFactory"].InnerText));
        }

        private void LoadRootMenus()
        {
            IRemotingPortalFactory proxyMgr = (IRemotingPortalFactory)CurrentAddinManager.GetAddin(ConfigNode["PortalFactory"].InnerText);
            ISecuritySystem securitySys = proxyMgr.GetProxy<ISecuritySystem>();
            ISystemStatCenter statCenter = (ISystemStatCenter) CurrentAddinManager.GetAddin("SystemStatCenter");
            IList<Module> modules = securitySys.GetRoleModuleList(statCenter.GetSystemStat().UserRole.PrimaryKey);

            rootMenus = new List<IMenuItem>();
            int menuOrderIndex = 0;
            foreach (Module module in modules)
            {
                SubMenuItem menuItem = new SubMenuItem();
                menuItem.Caption = module.ModuleCaption;
                menuItem.Enable = true;
                if (module.ModuleIcon != null)
                    menuItem.Icon = Bitmap.FromStream(new MemoryStream(module.ModuleIcon));
                menuItem.MenuId = module.ModuleKey;
                menuItem.OrderIndex = menuOrderIndex++;
                menuItem.Tag = module;
                menuItem.Visible = true;
                int itemOrderIndex = 0;
                foreach (Function subFunction in module.Functions)
                {
                    CommandMenuItem subItem = new CommandMenuItem();
                    subItem.Caption = subFunction.FunctionCaption;
                    subItem.Enable = true;
                    if (subFunction.IconData != null)
                        subItem.Icon = Bitmap.FromStream(new MemoryStream(subFunction.IconData));
                    subItem.MenuId = subFunction.FunctionKey;
                    subItem.OrderIndex = itemOrderIndex++;
                    subItem.PluginKey = subFunction.FunctionKey;
                    subItem.Tag = subFunction;
                    subItem.Visible = true;
                    menuItem.Items.Add(subItem);
                }
                if (menuItem.Items.Count > 0)
                    rootMenus.Add(menuItem);
            }
        }
    }
}